package com.py.credit.service.impl;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import com.alibaba.fastjson.JSONArray;
import com.py.credit.common.ServiceException;
import com.py.credit.common.logs.DebugLogger;
import com.py.credit.common.logs.ExceptionLogger;
import com.py.credit.dao.AuthorizonConfigDao;
import com.py.credit.dao.AuthorizonCubeDao;
import com.py.credit.dao.AuthorizonLogDao;
import com.py.credit.dao.AuthorizonSubjectDao;
import com.py.credit.entity.AuthorizonConfig;
import com.py.credit.entity.AuthorizonConfigModel;
import com.py.credit.entity.AuthorizonCube;
import com.py.credit.entity.AuthorizonLog;
import com.py.credit.entity.AuthorizonSubject;
import com.py.credit.entity.DataResult;
import com.py.credit.entity.Database;
import com.py.credit.entity.TableResult;
import com.py.credit.service.AuthorizationConfigService;
import com.py.credit.service.DataRelateService;
import com.py.credit.service.TableService;
import com.py.credit.service.excel.read.service.ExcelReadService;
import com.py.credit.utils.IpUtil;
import com.py.credit.utils.SQLBuilder;
import com.py.framework.core.common.Page;
import com.py.framework.core.entity.SysUserEntity;

@Service
public class AuthorizationConfigServiceImpl implements AuthorizationConfigService {

	@Autowired
	private AuthorizonConfigDao authorizonConfigDao;

	@Autowired
	private AuthorizonCubeDao authorizonCubeDao;

	@Autowired
	private AuthorizonLogDao authorizonLogDao;

	@Autowired
	private AuthorizonSubjectDao authorizonSubjectDao;
	@Autowired
	private DataRelateService dataRelateService;

	@Autowired
	private TableService tableService;

	@Autowired
	private DbServiceImpl dbService;

	@Autowired
	private ExcelReadService excelReadService;

	@Override
	@Transactional
	public int add(AuthorizonConfig authorizonConfig, String cubesStr, String subjectsStr) {

		authorizonConfigDao.insertSelective(authorizonConfig);

		Integer configId = authorizonConfig.getId();

		List<AuthorizonCube> cubes = JSONArray.parseArray(cubesStr, AuthorizonCube.class);

		if (cubes == null || cubes.size() < 1) {

			throw new ServiceException("授权查询信息资源不能为空");

		}

		List<AuthorizonSubject> subjects = JSONArray.parseArray(subjectsStr, AuthorizonSubject.class);

		if (subjects == null || subjects.size() < 1) {
			throw new ServiceException("查询主体信息不能为空");
		}

		for (AuthorizonSubject subject : subjects) {

			if (subject.getSubjectDbId() == null) {
				throw new ServiceException("主体类型不能为空");
			}

			if (String.valueOf(subject.getSubjectDbId()).equals("100001")) {

				if (StringUtils.isBlank(subject.getSubjectCode())) {

					throw new ServiceException("自然人主体信息码(身份证)不能为空");

				}

			} else if (StringUtils.isBlank(subject.getSubjectName()) && StringUtils.isBlank(subject.getSubjectCode())) {
				throw new ServiceException("主体名称和主体信息码不能都为空");
			}

		}

		if (!CollectionUtils.isEmpty(cubes)) {

			for (AuthorizonCube cube : cubes) {

				cube.setConfigId(configId);

				authorizonCubeDao.insertSelective(cube);
			}

		}

		if (!CollectionUtils.isEmpty(subjects)) {

			for (AuthorizonSubject subject : subjects) {

				subject.setConfigId(configId);

				for (AuthorizonCube cube : cubes) {

					if (String.valueOf(cube.getCubeDbId()).equals(String.valueOf(subject.getSubjectDbId()))) {

						subject.setCubeId(cube.getCubeId());

						authorizonSubjectDao.insertSelective(subject);
					}
				}

			}
		}

		return configId;

	}

	@Override
	@Transactional
	public void delete(int id) {

		authorizonConfigDao.deleteByPrimaryKey(id);

		authorizonCubeDao.deleteByConfigId(id);

		authorizonSubjectDao.deleteByConfigId(id);

	}

	@Override
	public List<Map<String, Object>> getAuthorizonSubjectList(Long id, String kId, String keyword) {

		return authorizonConfigDao.selectAuthorizonSubjectList(id, kId, keyword);
	}

	@Override
	public List<Map<String, String>> getAuthorizonCubeList(Long id, String kId) {
		return authorizonConfigDao.selectAuthorizonCubeList(id, kId);
	}

	@Override
	public void update(AuthorizonConfig authorizonConfig) {
		authorizonConfigDao.updateByPrimaryKey(authorizonConfig);

	}

	@Override
	public List<TableResult> getDetail(int kId, String keyword, String[] auTableName, String user,String deptName) {
		List<String> keywordColum = dataRelateService.getAssociationMetricCodesByDbId(kId);

		DebugLogger.debug("查询关键列-->", keywordColum);

		List<TableResult> tableList = new ArrayList<TableResult>();

		Set<String> table = new HashSet<String>();

		if (keywordColum != null && keywordColum.size() > 0) {

			String tybm = authorizonConfigDao.selectTybmBy(kId, keyword, keywordColum.get(0));

			DebugLogger.debug("tybm-->", tybm);

			if (tybm != null) {

				tableList = authorizonConfigDao.selectSearReourceDetail(kId, auTableName);

				for (TableResult tableResult : tableList) {

					try {

						table.add(tableResult.getTableNameCN());

						if (!CollectionUtils.isEmpty(tableResult.getColumns())) {

							List<DataResult> data = tableService.getData("t_" + tableResult.getTableNameEN(),
									tableResult.getColumns(), tybm);
							tableResult.setData(data);

						}
					} catch (Exception e) {

						ExceptionLogger.error(e);

					}

				}

				AuthorizonLog authorizonLog = new AuthorizonLog();

				authorizonLog.setSearchIp(IpUtil.getInstance().getIpAddr());

				authorizonLog.setUserName(user);
				
				authorizonLog.setDeptName(deptName);
				
				authorizonLog.setSearchSubjectName(keyword);
			
				Database db = dbService.getById(kId);

				authorizonLog.setSearchSubjectType(db == null ? "" : db.getName());

				authorizonLog.setSearchSubejectTable(table.toString());

				authorizonLogDao.insertSelective(authorizonLog);

			}
		}

		return tableList;
	}

	@Override
	public Set<String> parseFileToDB(String filePath, List<SysUserEntity> allUser, List<Map<String, String>> cubes,
			List<Database> dbList, String fileName) throws IOException {
		Set<String> ids = new HashSet<String>();
		Sheet sheet = excelReadService.readExcelFileForSheet(filePath);
		String[] columns = new String[] { "部门名称", "账号", "姓名", "截止日期", "信息资源表名称", "主体类别", "主体名称", "主体编码" };
		Map<String, String> checkHeader = excelReadService.checkHeader(sheet, columns);

		if (checkHeader == null || checkHeader.isEmpty()) {

			Sheet st = checkData(sheet, allUser, cubes, dbList);
			Map<String, AuthorizonConfigModel> assmableData = assmableData(st, allUser, dbList, cubes);

			ids = this.add(assmableData, fileName);

		} else {

			throw new ServiceException("excel 模板不符合要求");

		}

		return ids;

	}

	@Override
	@Transactional
	public Set<String> add(Map<String, AuthorizonConfigModel> assmableData, String fileName) {

		Set<String> ids = new HashSet<String>();

		for (Entry<String, AuthorizonConfigModel> entry : assmableData.entrySet()) {
			AuthorizonConfigModel authorizonConfigModel = entry.getValue();
			AuthorizonConfig authorizonConfig = new AuthorizonConfig();
			authorizonConfig.setApplicantAccount(authorizonConfigModel.getApplicantAccount());
			authorizonConfig.setApplicantName(authorizonConfigModel.getApplicantName());
			authorizonConfig.setApplyDeptId(authorizonConfigModel.getApplyDeptId());
			authorizonConfig.setApplyDeptName(authorizonConfigModel.getApplyDeptName());
			authorizonConfig.setExpiryDate(authorizonConfigModel.getExpiryDate());
			authorizonConfig.setApplicantId(authorizonConfigModel.getApplicantId());

			authorizonConfigDao.insertSelective(authorizonConfig);
			Integer id = authorizonConfig.getId();

			authorizonConfig.setApplyEvidence(fileName);

			authorizonConfigDao.updateByPrimaryKey(authorizonConfig);
			ids.add(String.valueOf(id));
			List<AuthorizonCube> cubes = authorizonConfigModel.getCubes();
			List<AuthorizonSubject> subjects = authorizonConfigModel.getSubjects();
			if (cubes != null) {

				for (AuthorizonCube cube : cubes) {

					cube.setConfigId(id);

					authorizonCubeDao.insertSelective(cube);

				}

			}

			if (subjects != null) {

				for (AuthorizonSubject subject : subjects) {

					subject.setConfigId(id);

					authorizonSubjectDao.insertSelective(subject);

				}

			}

		}

		return ids;

	}

	private Map<String, AuthorizonConfigModel> assmableData(Sheet st, List<SysUserEntity> allUser,
			List<Database> dbList, List<Map<String, String>> cubes) {

		Map<String, AuthorizonConfigModel> authorizonConfigModelMap = new HashMap<String, AuthorizonConfigModel>();

		int length = st.getLastRowNum();

		for (int rowIndex = 1; rowIndex <= length; rowIndex++) {

			List<AuthorizonCube> authorizonCubes = new ArrayList<AuthorizonCube>();
			List<AuthorizonSubject> authorizonSubjects = new ArrayList<AuthorizonSubject>();
			Row row = st.getRow(rowIndex);
			String dept = row.getCell(0).getStringCellValue();
			String account = row.getCell(1).getStringCellValue();
			String name = row.getCell(2).getStringCellValue();
			Date expiryDate = row.getCell(3).getDateCellValue();

			Long dataStr = expiryDate.getTime();
			String resource = row.getCell(4).getStringCellValue();

			String subjectType = row.getCell(5).getStringCellValue();
			String subjectName = row.getCell(6).getStringCellValue();
			String subjectCode = row.getCell(7).getStringCellValue();
			String key = dept.trim() + "_" + account.trim() + "_" + dataStr + "_" + resource.trim();

			if (authorizonConfigModelMap.containsKey(key)) {

				AuthorizonConfigModel authorizonConfigModel = authorizonConfigModelMap.get(key);

				List<AuthorizonSubject> subjects = authorizonConfigModel.getSubjects();

				AuthorizonSubject authorizonSubject = subjects.get(0);
				AuthorizonSubject subject = new AuthorizonSubject();

				subject.setDbName(subjectType);
				subject.setSubjectCode(subjectCode);
				subject.setSubjectName(subjectName);
				for (Map<String, String> cube : cubes) {

					String cubeName = cube.get("cubeName");

					String cubeId = cube.get("cubeId");

					if (resource.equals(cubeName)) {

						subject.setCubeId(Integer.valueOf(cubeId));
						break;

					}

				}

				subject.setSubjectDbId(authorizonSubject.getSubjectDbId());
				subjects.add(subject);

			} else {

				AuthorizonConfigModel authorizonConfigModel = new AuthorizonConfigModel();
				authorizonConfigModel.setApplicantAccount(account);
				authorizonConfigModel.setApplicantName(name);
				authorizonConfigModel.setApplyDeptName(dept);

				authorizonConfigModel.setExpiryDate(expiryDate);

				AuthorizonCube oneCube = new AuthorizonCube();
				AuthorizonSubject subject = new AuthorizonSubject();
				for (Database db : dbList) {

					if (db.getName().equals(subjectType)) {
						oneCube.setCubeDbId(db.getId());
						subject.setSubjectDbId(db.getId());
						break;
					}

				}

				for (Map<String, String> cube : cubes) {

					String cubeName = cube.get("cubeName");

					String cubeId = cube.get("cubeId");

					if (resource.equals(cubeName)) {

						oneCube.setCubeId(Integer.valueOf(cubeId));
						subject.setCubeId(Integer.valueOf(cubeId));
						break;

					}

				}

				for (SysUserEntity user : allUser) {

					String username = user.getUsername();
					long id = user.getId();
					if (account.equals(username)) {

						authorizonConfigModel.setApplicantId((int) id);
						break;

					}

				}

				oneCube.setDbName(subjectType);

				// oneCube.setCubeDeptName(dept);

				// oneCube.setCubeDeptId(cubeDeptId);

				oneCube.setCubeName(resource);

				authorizonCubes.add(oneCube);

				subject.setDbName(subjectType);
				subject.setSubjectCode(subjectCode);
				subject.setSubjectName(subjectName);

				authorizonSubjects.add(subject);
				authorizonConfigModel.setCubes(authorizonCubes);

				authorizonConfigModel.setSubjects(authorizonSubjects);

				authorizonConfigModelMap.put(key, authorizonConfigModel);

			}

		}

		return authorizonConfigModelMap;

	}

	private Sheet checkData(Sheet st, List<SysUserEntity> allUser, List<Map<String, String>> cubes,
			List<Database> dbList) {

		List<Map<String, String>> deptAccountNames = new ArrayList<Map<String, String>>();

		Set<String> cubesSet = new HashSet<String>();

		int length = st.getLastRowNum();

		if (length < 1) {

			throw new ServiceException("excel不包含数据");

		}

		for (int rowIndex = 1; rowIndex <= length; rowIndex++) {

			Row row = st.getRow(rowIndex);

			if (row == null) {
				throw new ServiceException("数据不符合要求,第【" + rowIndex + "】行数据全为空");
			}

			if (row.getCell(0) == null || StringUtils.isBlank(row.getCell(0).getStringCellValue())) {

				throw new ServiceException("数据不符合要求,第【" + rowIndex + "】行数据,部门名称不能为空");
			}

			if (row.getCell(1) == null || StringUtils.isBlank(row.getCell(1).getStringCellValue())) {
				throw new ServiceException("数据不符合要求,第【" + rowIndex + "】行数据,账号不能为空");
			}

			if (row.getCell(2) == null || StringUtils.isBlank(row.getCell(2).getStringCellValue())) {
				throw new ServiceException("数据不符合要求,第【" + rowIndex + "】行数据,姓名不能为空");
			}

			if (row.getCell(3) == null || row.getCell(3).getCellType() != HSSFCell.CELL_TYPE_NUMERIC) {

				throw new ServiceException("数据不符合要求,第【" + rowIndex + "】行数据,截止日期不能为空且必须是时间格式yyyy/mm/dd");
			}

			if (row.getCell(4) == null || StringUtils.isBlank(row.getCell(4).getStringCellValue())) {
				throw new ServiceException("数据不符合要求,第【" + rowIndex + "】行数据,信息资源表名称不能为空");
			}

			if (row.getCell(5) == null || StringUtils.isBlank(row.getCell(5).getStringCellValue())) {
				throw new ServiceException("数据不符合要求,第【" + rowIndex + "】行数据,主体类别不能为空");
			}

			if ((row.getCell(6) == null || StringUtils.isBlank(row.getCell(6).getStringCellValue()))
					&& (row.getCell(7) == null || StringUtils.isBlank(row.getCell(7).getStringCellValue()))) {
				throw new ServiceException("数据不符合要求,第【" + rowIndex + "】行数据,主体名称和主体编码不能都为空");
			}

			String dept = row.getCell(0).getStringCellValue();
			String account = row.getCell(1).getStringCellValue();
			String name = row.getCell(2).getStringCellValue();
			String resource = row.getCell(4).getStringCellValue();
			String subjectType = row.getCell(5).getStringCellValue();

			boolean hit = false;

			for (Database db : dbList) {

				if (db.getName().equals(subjectType)) {

					hit = true;
					break;

				}

			}

			if (!hit) {
				throw new ServiceException("数据不符合要求,第【" + rowIndex + "】行数据,主体类别【" + subjectType + "】不存在");
			}

			cubesSet.add(resource);

			Map<String, String> deptAccountName = new HashMap<String, String>();

			deptAccountName.put("rowIndex", String.valueOf(rowIndex));

			deptAccountName.put("value", dept + "_" + account + "_" + name);

			deptAccountNames.add(deptAccountName);

		}

		for (Map<String, String> map : deptAccountNames) {

			String value = map.get("value");

			String rowIndex = map.get("rowIndex");

			int hitCount = 0;

			for (SysUserEntity user : allUser) {

				String realName = user.getRealName();

				String userName = user.getUsername();

				String officeName = user.getOfficeName();

				if (value.equals(officeName + "_" + userName + "_" + realName)) {

					hitCount++;

					break;

				}

			}

			if (hitCount == 0) {
				throw new ServiceException("数据不符合要求,第【" + rowIndex + "】行数据,部门_账号_姓名 【" + value + "】对应关系不存在");
			}

		}

		for (String cube : cubesSet) {

			int hitCount = 0;

			for (Map<String, String> map : cubes) {

				String cubeName = map.get("cubeName");

				if (cube.equals(cubeName)) {

					hitCount++;

					break;

				}

			}
			if (hitCount == 0) {
				throw new ServiceException("数据不符合要求,信息资源表名称 【" + cube + "】 在一站式核查目录中不存在");
			}

		}

		return st;

	}

	@Override
	public List<Map<String, Object>> getByConditionForPage(String userName, List<String> showColumns,
			String[] additionalColumns, String condition, Page page) {

		if (CollectionUtils.isEmpty(showColumns)) {

			throw new ServiceException("至少选择一列导出");

		}
		List<String> conditions = SQLBuilder.createConditionSql(condition);

		return authorizonConfigDao.selectByConditionForPage(userName, showColumns, additionalColumns, conditions, page);
	}

	@Override
	public Map<String, Object> getAuthDetail(int id) {

		Map<String, Object> detail = new HashMap<String, Object>();

		AuthorizonConfig config = authorizonConfigDao.selectByPrimaryKey(id);

		List<AuthorizonCube> cubes = authorizonCubeDao.selectByConfigId(id);

		List<AuthorizonSubject> subjects = authorizonSubjectDao.selectByConfigId(id);

		detail.put("config", config);
		detail.put("cubes", cubes);
		detail.put("subjects", subjects);

		return detail;
	}

	@Override
	public List<Map<String, String>> getSharingContentCubesByType(String type) {

		List<Map<String, String>> cubes = authorizonConfigDao.selectSharingContentCubesByType(type);

		return cubes;
	}

	@Override
	public AuthorizonConfig getById(int id) {
		// TODO Auto-generated method stub
		return authorizonConfigDao.selectByPrimaryKey(id);
	}

	@Override
	public void updateApplyStatusByID(String id,String apply_status,String shyj) {
		authorizonConfigDao.updateApplyStatusByID(id,apply_status,shyj);
		
	}

	@Override
	public List<Map<String, String>> selectShdataForPage(String applicant_name, String deptId,String apply_dept_name,Page page) {
		
		return authorizonConfigDao.selectShdataForPage(applicant_name,deptId,apply_dept_name,page);
	}

}
